<?php

/**
 * Class ServerController
 */
class v1Controller extends Yaf_Controller_Abstract
{
    public $request;
    public $response;
    public $data;
    public $config;
    public $merchant;
    const SERVER_SECRET = '7d428e5965220f76551bda7671ff4710';

    ######################
    // 注册节点
    function register()
    {

    }

    // 获取配置
    function getconf()
    {
        // http , https , tcp
    }

    // 资源消耗状态上报
    function status()
    {

    }

    // 流量上报
    function traffic()
    {

    }

    #######################
    function doAction()
    {
        $method = strtolower($this->data['cmd']);
        $this->log($this->data);
        if (method_exists($this, $method)) {
            $this->$method();
        } else {
            $this->result(10006, '服务受限');
        }
    }

    // 初始化
    function init()
    {
        Yaf_Dispatcher::getInstance()->disableView();
        header('Access-Control-Allow-Origin:*');
        header('Access-Control-Allow-Methods:POST,GET');
        $this->request = $this->getRequest();
        $this->response = $this->getResponse();
        $this->config = Yaf_Registry::get('config');
        $this->check_access();
    }

    // 校验协议
    private function check_access()
    {
        /**
         * 公共参数
         * cmd  =
         * time = 时间戳(s)
         * encrypt = md5
         * sign = 加密算出的字符串
         *
         * 其他参数按照实际CMD对应参数为准
         *
         *
         * 1. 准备所有需要传过来的参数
         * 2. 将所有参数按照参数名字母从a-z顺序排序并实现此种加密 sign = md5(key1=val1&key2=val2....&secret=xxxxx)
         * 3. 将所有参数(包含 sign)用POST application/json 方式请求至 API地址
         * 4. 接受返回 {code:0,msg:'xxx',data:{xx:xx,xx:xx}}
         */
        // 获取data
        $data = file_get_contents('php://input');
        $this->log('请求: ' . $data);
        $data = json_decode($data, true);
        if (is_array($data) && $data && isset($data['sign'])) {
            ksort($data);
            $this->data = $data;
            // 验证请求合法性
            $ip = Helper::ip();
            $allow_ips = explode(',', $this->config->game->servers);
            if ($allow_ips) {
                if (!in_array($ip, $allow_ips)) {
                    $this->log($ip . ' 无权访问 ');
                    $this->result(10003, 'IP无权访问');
                }
            }
            // 超时
            if (time() - $data['time'] > 5) $this->result(10003, '超时请求');
            // 验签
            $sign = $this->get_sign($data);
            if ($sign == $data['sign']) return;
            $this->result(10003, '校验失败');
        }
        $this->result();
    }

    // 获取POST参数
    protected function post($var, $default = null)
    {
        $value = $this->request->getPost($var);
        if (is_array($value)) return $value;
        if (is_string($value)) return trim($value);
        if (!$value) return $default;
    }

    // 获取GET参数
    protected function get($var, $default = null)
    {
        $value = $this->request->getQuery($var);
        if (is_array($value)) return $value;
        if (is_string($value)) return trim($value);
        if (!$value) return $default;
    }

    // 返回
    function result($code = null, $msg = '参数错误', $data = array())
    {
        header('content-type:application/json');
        if (is_null($code)) $code = '10001';
        $return = array(
            'code' => intval($code),
            'msg' => $msg
        );
        if ($data) $return['data'] = $data;
        $this->log("返回[{$this->data['cmd']}]: " . json_encode($return, JSON_UNESCAPED_UNICODE));
        die(json_encode($return, JSON_UNESCAPED_UNICODE));
    }

    // 构造协议参数
    private function get_sign($data)
    {
        ksort($data);
        $_ = '';
        foreach ($data as $k => $v) {
            if ($k != 'sign') $_ .= "{$k}={$v}&";
        }
        $sign = '';
        switch (strtoupper($data['encrypt'])) {
            case 'MD5':
            default:
                $sign = md5($_ . 'secret=' . self::SERVER_SECRET);
        }
        return $sign;
    }

    // 日志
    private function log($data, $path = null)
    {
        $path = $path ?? __CLASS__;
        Logger::getInterface($path)->error($data);
    }
}